<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <canvas></canvas>
</body>
<script>
    const cvs = document.querySelector('canvas')
    const ctx = cvs.getContext('2d', {
        willReadFrequently: true
    })
    let randomColor = [0, 255, 0, 255]

    function init() {
        const img = new Image()
        img.onload = () => {
            cvs.width = img.width
            cvs.height = img.height
            ctx.drawImage(img, 0, 0)
        }
        img.src = './dog.jpg'
    }

    init()

    cvs.addEventListener('click', (e) => {
        const x = e.offsetX, y = e.offsetY;
        const imgData = ctx.getImageData(0, 0, cvs.width, cvs.height)
        const clickColor = getColor(x, y, imgData)
        randomColor = [Math.floor(Math.random() * 250), Math.floor(Math.random() * 250), Math.floor(Math.random() * 250), 255]
        // function changeColor(x, y) {
        //     if (x < 0 || x >= cvs.width || y < 0 || y >= cvs.height) {
        //         return
        //     }
        //     const i = pointIndex(x, y)
        //     const color = getColor(x, y, imgData)
        //     if (diffColor(color, clickColor) > 100) {
        //         return
        //     }
        //     if (diffColor(color, randomColor) === 0) {
        //         return
        //     }
        //     imgData.data.set(randomColor, i)
        //     changeColor(x + 1, y);
        //     changeColor(x - 1, y);
        //     changeColor(x, y + 1);
        //     changeColor(x, y - 1);
        // }
        // 通过队列对递归进行优化
        function changeColor(x, y) {
            const queue = [];
            queue.push([x, y]); // 将当前点入队列

            while (queue.length > 0) { // 判断队列是否为空
                const [currX, currY] = queue.shift(); // 取出队首元素

                if (currX < 0 || currX >= cvs.width || currY < 0 || currY >= cvs.height) {
                    continue; // 越界，处理下一个元素
                }

                const i = pointIndex(currX, currY);
                const color = getColor(currX, currY, imgData);

                if (diffColor(color, clickColor) > 100) {
                    continue; // 颜色差异过大，处理下一个元素
                }

                if (diffColor(color, randomColor) === 0) {
                    continue; // 已经是目标颜色了，处理下一个元素
                }

                imgData.data.set(randomColor, i); // 设置为绿色

                // 将上、下、左、右四个方向的点入队列
                queue.push([currX + 1, currY]);
                queue.push([currX - 1, currY]);
                queue.push([currX, currY + 1]);
                queue.push([currX, currY - 1]);
            }
        }
        changeColor(x, y);
        ctx.putImageData(imgData, 0, 0)
    })

    function pointIndex(x, y) {
        return (y * cvs.width + x) * 4
    }

    function getColor(x, y, imgData) {
        const i = pointIndex(x, y)
        return [
            imgData.data[i],
            imgData.data[i + 1],
            imgData.data[i + 2],
            imgData.data[i + 3],
        ]
    }

    function diffColor(color1, color2) {
        return (
            Math.abs(color1[0] - color2[0]) +
            Math.abs(color1[1] - color2[1]) +
            Math.abs(color1[2] - color2[2]) +
            Math.abs(color1[3] - color2[3])
        )
    }
</script>

</html>